/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/

package com.aphrodite.ui.widgets;

import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

import com.aphrodite.image.ColorUtil;
import com.aphrodite.ui.graphics.GraphicUtil;
import com.aphrodite.ui.schema.ToolbarButton;
import com.aphrodite.util.geom.GeomUtil;

//pointer pressed tbd
/**
 * Toolbar widget
 * <p>
 * <img src="../../../resources/aphro_toolbar.png">
 * </p>
 * 
 * @author kentelt
 * 
 */
public final class Toolbar extends TraversableWidget {

	private final class Ani extends TimerTask {
		public void run() {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			isFired = false;
			reDrawWidget();
			super.cancel();
		}
	}

	/* Padding at the left of the toolbar */
	private int btnLeftPad = 2;
	/* Padding at the top of the toolbar */
	private int btnTopPad = 2;
	private final Vector buttons;
	/* currently selected index */
	private int currentIndex;
	/* indicates if a toolbar button is in fired state */
	private volatile boolean isFired;
	private short layout = LAYOUT_HORIZONTAL;
	// private ClickListener listener;
	/* Thickness of the separator bar */
	private int sepThickness = 3;

	private int shadowColor;
	private int toolBarHt;
	private int toolBarWth;
	private int toolTipBG = 0x000000;
	private int toolTipHeight;

	public Toolbar(Theme theme) {
		this(theme, LAYOUT_HORIZONTAL);
	}

	public Toolbar(Theme theme, short layout) {
		super(theme, 0, 0);
		this.layout = layout;
		buttons = new Vector();
		updateModel();
	}

	/**
	 * Add toolbar buttons
	 * 
	 * @param button
	 */
	public void addButton(ToolbarButton button) {
		buttons.addElement(button);
		calcToolbarWidth();
		reDrawWidget();
	}

	private void calcToolbarWidth() {
		ToolbarButton tmpBtn;
		if (!buttons.isEmpty()) {

			if (layout == LAYOUT_HORIZONTAL) {

				this.toolBarWth = btnLeftPad;
				int tallest = 0;

				for (int i = 0; i < buttons.size(); i++) {
					tmpBtn = (ToolbarButton) buttons.elementAt(i);
					if (tmpBtn.icon != null) {
						toolBarWth += tmpBtn.icon.getWidth() + btnLeftPad;
						if (tmpBtn.icon.getHeight() > tallest)
							tallest = tmpBtn.icon.getHeight();
					} else if (tmpBtn.toolTip == null) {// is a separator
						toolBarWth += sepThickness + btnLeftPad;
					}
				}
				this.toolBarHt = tallest + (btnTopPad * 2);
				this.height = toolBarHt + toolTipHeight;
				this.width = toolBarWth;

			} else {

				this.toolBarHt = btnLeftPad;// _
				int mostBroad = 0;
				int biggestText = 0;/*
									 * we this because the capture sets the clip
									 */
				int wdth = 0;
				for (int i = 0; i < buttons.size(); i++) {
					tmpBtn = (ToolbarButton) buttons.elementAt(i);
					if (tmpBtn.icon != null) {
						toolBarHt += tmpBtn.icon.getHeight() + btnLeftPad;
						if (tmpBtn.icon.getWidth() > mostBroad) {
							mostBroad = tmpBtn.icon.getWidth();
						}
					}
					if (tmpBtn.toolTip != null) {
						wdth = 0;
						if (theme.bmFont != null) {
							wdth = theme.bmFont.stringWidth(tmpBtn.toolTip);
						} else {
							wdth = theme.widgetFont.stringWidth(tmpBtn.toolTip);
						}
						if (wdth > biggestText)
							biggestText = wdth;
					} else {
						if (tmpBtn.icon == null) {/* just to be sure */
							toolBarHt += sepThickness + btnLeftPad;
						}
					}
				}
				this.toolBarWth = mostBroad + (btnTopPad * 2);
				this.width = mostBroad + (biggestText + 4) + (btnTopPad * 2);
				this.height = toolBarHt;
			}

		}
		sizeChanged(width, height);
	}

	private int calcTTX(int currentX, int iconWidth, int stringW) {
		return (currentX + stringW > width) ? currentX + iconWidth - stringW : currentX;
	}

	public void cleanUp() {
		buttons.removeAllElements();
		// isSeparator = null;
	}

	private boolean decreaseIndex() {
		if (currentIndex > 0) {
			currentIndex--;
		} else {
			location = UPPER;
			isInFocus = false;
			return false;
		}
		// else if (currentIndex == 0) {
		// currentIndex = buttons.length - 1;
		// }
		doBckSeprtorCheck((ToolbarButton) buttons.elementAt(currentIndex));
		reDrawWidget();
		return true;
	}

	private void doBckSeprtorCheck(ToolbarButton btn) {
		if (btn.icon == null && btn.toolTip == null) {
			currentIndex--;
			currentIndex = (currentIndex < 0) ? buttons.size() - 1 : currentIndex--;
		}
	}

	private void doFwdSeprtorCheck(ToolbarButton btn) {
		if (btn.icon == null && btn.toolTip == null) {
			currentIndex++;
			// System.out.println("The current index is a separator");
			// currentIndex = (currentIndex < buttons.size() - 1) ?
			// currentIndex++ : 0;
			currentIndex = (currentIndex < buttons.size()) ? currentIndex++ : 0;
		}
	}

	private void drawHorzToolbar(Graphics g) {
		try {

			int currentPad = btnLeftPad;
			int ttX;
			ToolbarButton tmpBtn;
			for (int i = 0; i < buttons.size(); i++) {
				tmpBtn = (ToolbarButton) buttons.elementAt(i);
				if (tmpBtn.icon != null) {
					if (i == currentIndex) {

						g.setColor(isFired ? 0xffffff : shadowColor);
						g.drawRect(currentPad, btnTopPad, tmpBtn.icon.getWidth(), tmpBtn.icon.getHeight());
						g.setColor(isFired ? shadowColor : 0xffffff);
						g.drawLine(currentPad, btnTopPad, currentPad + tmpBtn.icon.getWidth(), btnTopPad);// __
						g.drawLine(currentPad, btnTopPad, currentPad, btnTopPad + tmpBtn.icon.getHeight());// |

						g.drawImage(tmpBtn.icon, (isFired) ? currentPad + 1 : currentPad, (isFired) ? btnTopPad + 1
								: btnTopPad, 0);

						// draw the tool tip
						if (tmpBtn.toolTip != null) {
							if (theme.bmFont != null) {
								ttX = calcTTX(currentPad, tmpBtn.icon.getWidth(), theme.bmFont
										.stringWidth(tmpBtn.toolTip));
								/* tool tip rectangle */
								g.setColor(toolTipBG);
								GraphicUtil.fillRect(g, 180, ttX, toolBarHt,
										theme.bmFont.stringWidth(tmpBtn.toolTip) + 4, toolTipHeight);
								g.setColor(theme.fgColor);
								theme.bmFont.drawString(g, tmpBtn.toolTip, ttX + 2, toolBarHt + 2, 0);
							} else {

								g.setFont(theme.widgetFont);
								ttX = calcTTX(currentPad, tmpBtn.icon.getWidth(), g.getFont().stringWidth(
										tmpBtn.toolTip));
								/* tool tip rectangle */
								g.setColor(toolTipBG);
								GraphicUtil.fillRect(g, 180, ttX, toolBarHt,
										g.getFont().stringWidth(tmpBtn.toolTip) + 4, toolTipHeight);
								g.setColor(theme.fgColor);
								g.drawString(tmpBtn.toolTip, ttX + 2, toolBarHt + 2, 0);
							}
						}
					} else {

						/* i !=current index */
						if (tmpBtn.isEnabled) {
							g.setColor(0xffffff);
							g.drawRect(currentPad, btnTopPad, tmpBtn.icon.getWidth(), tmpBtn.icon.getHeight());
							g.setColor(shadowColor);
							g.drawLine(currentPad, btnTopPad, currentPad + tmpBtn.icon.getWidth(), btnTopPad);// __
							g.drawLine(currentPad, btnTopPad, currentPad, btnTopPad + tmpBtn.icon.getHeight());// |
						}
						g.drawImage(tmpBtn.icon, currentPad, btnTopPad, 0);
					}
					currentPad += tmpBtn.icon.getWidth();
				} else if (tmpBtn.toolTip == null) {
					/* is a separator */
					g.setColor(shadowColor);// 0x808080
					g.drawRect(currentPad, btnTopPad, sepThickness, toolBarHt - (btnTopPad * 2) - 1);
					g.setColor(0xffffff);
					g.drawLine(currentPad, btnTopPad, currentPad + sepThickness, btnTopPad);// _
					g.drawLine(currentPad, btnTopPad + 1, currentPad, toolBarHt - (btnTopPad * 2) + 1);// |
					currentPad += sepThickness;
				}
				currentPad += btnLeftPad;
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println(e.toString());
		}
	}

	private void drawVertToolbar(Graphics g) {
		int currentPad = btnLeftPad;
		ToolbarButton tmpBtn;
		for (int i = 0; i < buttons.size(); i++) {
			tmpBtn = (ToolbarButton) buttons.elementAt(i);
			if (tmpBtn.icon != null) {
				if (i == currentIndex) {
					g.setColor(isFired ? 0xffffff : shadowColor);
					g.drawRect(btnTopPad, currentPad, tmpBtn.icon.getWidth(), tmpBtn.icon.getHeight());
					g.setColor(isFired ? shadowColor : 0xffffff);
					g.drawLine(btnTopPad, currentPad, btnTopPad + tmpBtn.icon.getWidth(), currentPad);
					g.drawLine(btnTopPad, currentPad, btnTopPad, currentPad + tmpBtn.icon.getHeight() - 1);
					g.drawImage(tmpBtn.icon, (isFired) ? btnTopPad + 1 : btnTopPad, (isFired) ? currentPad + 1
							: currentPad, 0);
					/* Draw the tool tip */
					if (tmpBtn.toolTip != null) {
						if (theme.bmFont != null) {
							g.setColor(toolTipBG);
							GraphicUtil.fillRect(g, 180, toolBarWth, currentPad, theme.bmFont
									.stringWidth(tmpBtn.toolTip) + 4, toolTipHeight);
							g.setColor(theme.fgColor);
							theme.bmFont.drawString(g, tmpBtn.toolTip, toolBarWth + 2, currentPad + 2, 0);
						} else {
							g.setFont(theme.widgetFont);
							g.setColor(toolTipBG);
							GraphicUtil.fillRect(g, 180, toolBarWth, currentPad, g.getFont()
									.stringWidth(tmpBtn.toolTip) + 4, toolTipHeight);
							g.setColor(theme.fgColor);
							g.drawString(tmpBtn.toolTip, toolBarWth + 2, currentPad + 2, 0);
						}
					}
				} else {
					if (tmpBtn.isEnabled) {
						g.setColor(0xffffff);
						g.drawRect(btnTopPad, currentPad, tmpBtn.icon.getWidth(), tmpBtn.icon.getHeight());
						g.setColor(shadowColor);
						g.drawLine(btnTopPad, currentPad, btnTopPad + tmpBtn.icon.getWidth(), currentPad);
						g.drawLine(btnTopPad, currentPad, btnTopPad, currentPad + tmpBtn.icon.getHeight() - 1);
					}
					g.drawImage(tmpBtn.icon, btnTopPad, currentPad, 0);
				}
				currentPad += tmpBtn.icon.getHeight();
			} else if (tmpBtn.toolTip == null) {
				/* Draw the separator */
				g.setColor(shadowColor);// 0x808080
				g.drawRect(btnTopPad, currentPad, toolBarWth - (btnTopPad * 2) - 1, sepThickness);
				g.setColor(0xffffff);
				g.drawLine(btnTopPad, currentPad, btnTopPad + toolBarWth - (btnTopPad * 2) - 1, currentPad);// -
				g.drawLine(btnTopPad, currentPad, btnTopPad, currentPad + sepThickness);// |
				currentPad += sepThickness;
			}
			currentPad += btnLeftPad;
		}
	}

	public void fire() {
		if (!isFired) {
			isFired = true;
			reDrawWidget();
			Timer timer = new Timer();
			timer.schedule(new Ani(), 0);
			super.fire();
		}
	}

	public ToolbarButton getSelectedButton() {
		return (!buttons.isEmpty()) ? (ToolbarButton) buttons.elementAt(getSelectedIndex()) : null;
	}

	public int getSelectedIndex() {
		return currentIndex;
	}

	private boolean increaseIndex() {
		if (currentIndex < buttons.size() - 1) {
			currentIndex++;
		} else {
			location = LOWER;
			isInFocus = false;
			return false;
		}
		// else if (currentIndex == buttons.length - 1) {
		// currentIndex = 0;
		// }
		doFwdSeprtorCheck((ToolbarButton) buttons.elementAt(currentIndex));
		reDrawWidget();
		return true;
	}

	public boolean moveDown() {
		return increaseIndex();
	}

	public boolean moveLeft() {
		return decreaseIndex();
	}

	public boolean moveRight() {
		return increaseIndex();
	}

	public boolean moveUp() {
		return decreaseIndex();
	}

	public boolean pointerPress(int px, int py) {
		if (isVisible && GeomUtil.withinBounds(px, py, x, y, toolBarWth, toolBarHt)) {
			// find the coordinate point within the widget
			final int contentX = px - x;
			final int contentY = py - y;
			ToolbarButton tmpBtn;
			int currentPos = btnLeftPad;
			System.out.println("current X " + contentX + " current Y" + contentY);
			for (int i = 0; i < buttons.size(); i++) {
				tmpBtn = (ToolbarButton) buttons.elementAt(i);
				if (tmpBtn.icon != null) {
					if (GeomUtil.withinBounds(contentX, contentY, layout == LAYOUT_HORIZONTAL ? currentPos : 0,
							layout == LAYOUT_HORIZONTAL ? 0 : currentPos, tmpBtn.icon.getWidth(), tmpBtn.icon
									.getHeight())) {
						currentIndex = i;
						break;
					}
					currentPos += (layout == LAYOUT_HORIZONTAL) ? tmpBtn.icon.getWidth() : tmpBtn.icon.getHeight();
				} else {/* its a separator */
					currentPos += sepThickness;
				}
				currentPos += btnLeftPad;
			}
			isFired = true;
			reDrawWidget();
			return true;
		}
		return false;
	}

	public boolean pointerRelease(int px, int py) {
		if (isVisible && GeomUtil.withinBounds(px, py, x, y, toolBarWth, toolBarHt)) {
			isFired = false;
			reDrawWidget();
			super.fire();
			return true;
		}
		return false;
	}

	public void render(Graphics g) {
		if (!isVisible)
			return;
		capture(g, toolBarWth, toolBarHt, true);
		if (layout == LAYOUT_HORIZONTAL)
			drawHorzToolbar(g);
		else
			drawVertToolbar(g);
		release(g, toolBarWth, toolBarHt, true);
	}

	/**
	 * 
	 * @param pad
	 *            padding between tool buttons(in pixels).Default is 2px.
	 */
	public void setButtonPad(int pad) {
		this.btnLeftPad = pad;
		updateModel();
		reDraw();
		stateChanged(this);
	}

	/**
	 * 
	 * 
	 * @param pad
	 *            on the and bottom of the tool buttons(in pixels). Default is
	 *            2px
	 */
	public void setButtonTopPad(int pad) {
		this.btnTopPad = pad;
		updateModel();
		reDraw();
		stateChanged(this);
	}

	// public void setFont(Font font) {
	// super.setFont(font);
	// updateModel();
	// reDrawWidget();
	// }

	public void setLayout(short layout) {
		this.layout = layout;
		updateModel();
		reDraw();
		stateChanged(this);
	}

	/**
	 * Background color of the tooltip
	 * 
	 * @param color
	 */
	public void setToolTipBG(int color) {
		toolTipBG = color;
	}

	protected boolean traverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout) {
		if (dir == Canvas.DOWN || dir == Canvas.RIGHT) {
			if (location == UPPER) {
				location = IN;
				return true;
			}
			if ((dir == Canvas.DOWN && layout == LAYOUT_VERTICAL)
					|| (dir == Canvas.RIGHT && layout == LAYOUT_HORIZONTAL)) {
				increaseIndex();
			} else {
				return false;
			}
		} else if (dir == Canvas.UP || dir == Canvas.LEFT) {
			if (location == LOWER) {
				location = IN;
				return true;
			}
			if (dir == Canvas.UP && layout == LAYOUT_VERTICAL) {
				decreaseIndex();
			} else if (dir == Canvas.LEFT && layout == LAYOUT_HORIZONTAL) {
				decreaseIndex();
			} else {
				return false;
			}
		}
		return true;
	}

	protected void updateModel() {
		shadowColor = ColorUtil.adjustBrightness(ColorUtil.covertToGrayscale(theme.bgColor), -40);
		// this.isSeparator = new boolean[buttons.size()];
		if (theme.bmFont != null) {
			this.toolTipHeight = (theme.bmFont.getHeight() + 4);
		} else {
			this.toolTipHeight = theme.widgetFont.getHeight() + 4;
		}
		// calcToolbarWidth();
	}
}
